package filter;

import javax.servlet.*;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.URL;
import java.util.*;

/**
 * 敏感词汇过滤器
 * 1. 对request对象进行增强：增强获取参数相关方法。
 * 2. 放行：传递代理对象。
 */
public class SensitiveWordsFilter implements Filter {
    private List<String> wordsList = new ArrayList<String>();

    public void destroy() {
    }

    public void doFilter(final ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //1.创建代理对象，增强获取参数值的方法(该方法用于获取表单填写的信息)
        /**
         * 动态代理增强Request对象
         * 三个固定参数：
         *      1.类加载器：真实对象.getClass().getClassLoader()
         *      2.接口数组：真实对象.getClass().getInterfaces()
         *      3.处理器：new InvocationHandler()
         */
        ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
            /**
             * 代理逻辑编写的方法：代理对象调用的所有方法都会触发该方法执行
             * @param proxy 代理对象
             * @param method 代理对象调用的方法，被封装为一个对象
             * @param args 代理对象调用方法时,传递的所有实参,被封装为一个数组
             * @return
             * @throws Throwable
             */
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //判断是否是getParameter方法
                if (method.getName().equals("getParameter")) {
                    /*
                     * String getParameter(String name)
                     */
                    String value = (String) method.invoke(req, args);//返回从表单获取到的属性值
                    //增强返回值
                    if (null != value) {
                        //有返回值，遍历敏感字符
                        for (String word : wordsList) {
                            //返回值中包含敏感字符，替换为***
                            if (value.contains(word)) {
                                value = value.replaceAll(word, "***");
                            }
                        }
                    }
                    return value;//返回被修改后的返回值
                    //判断是否是getParameter方法
                } else if (method.getName().equals("getParameterMap")) {
                    /*
                     * Map<String,String[]> getParameterMap()
                     */
                    Map<String,String[]> map = new HashMap<String,String[]>((Map) method.invoke(req, args));//返回从表单获取到的由属性名和属性值组成的map
                    if (!map.isEmpty()) {
                        //遍历map
                        Set<String> keySet = map.keySet();
                        for (String key : keySet) {
                            //获取每一个属性名对应的属性值
                            String[] valueArray = map.get(key);
                            //遍历敏感词汇
                            for (String word : wordsList) {
                                String value = String.valueOf(valueArray[0]);
                                if (value.contains(word)){
                                    //如果属性值包含敏感词，将敏感词替换为"***"
                                    valueArray[0] = value.replaceAll(word, "***");
                                    map.put(key,valueArray);
                                }
                            }
                        }
                    }
                    return map;
                } else {
                    Object obj = method.invoke(req, args);
                    return obj;
                }
            }
        });
        //放行时要放行代理对象
        chain.doFilter(proxy_req, resp);
    }

    public void init(FilterConfig config) throws ServletException {
        try {
            //加载敏感词汇
            //1.获取文件路径
            URL resource = SensitiveWordsFilter.class.getResource("words.txt");
            String path = resource.getPath();
            //2.读取文件
            InputStreamReader isr = new InputStreamReader(new FileInputStream(path), "utf-8");
            BufferedReader br = new BufferedReader(isr);
            //3.将文件的每一行数据添加到list中
            String line = null;
            while (null != (line = br.readLine())) {
                wordsList.add(line);
            }
            br.close();
            System.out.println(wordsList);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
